﻿using StockTradTest.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace StockTradTest
{
    //交易状态
    public enum TradStatus
    {
        NotReal,
        NotInSellOrBuy,
        InSellOrBuy,
    }
    //交易指令集
    public class TestTradBase
    {
        //交易手续费,佣金万1.6，最低5，双边；印花千一，卖出收取
        private const double myCommissionRate = 0.00016;
        private const double minCommission = 5;
        private const double myTax = 0.0001;
        public static bool isRecord = false;
        public string record = "";
        public int date;
        public static bool realTime = false;
        private static List<TradStock> buyStocks;
        private static List<TradStock> sellStocks;
        public static bool isOnClound = true;
        public double fakeFund = 500000;
        public List<MyStock> fakeStocks = new List<MyStock>();
        public struct TradStock
        {
            public string tCode;
            public int tNum;
            public double tPrice;

        }
        //默认状态初始化我的账户
        public void InitalMyAccount()
        {
            MyAccount myAccount = new MyAccount
            {
                ID = 1,
                AccountName = "Test",
                AccountPassword = "Test",
                Fund = 500000
            };
            InitalMyAccountWithData(false,true,myAccount);

        }
        /// <summary>
        /// 账户初始化
        /// </summary>
        /// <param name="real">是否实时测试</param>
        /// <param name="reWrite">是否更新现有账号及股票信息</param>
        /// <param name="myAccount">账号</param>
        /// <param name="myStocks">现有的股票信息</param>
        public void InitalMyAccountWithData(bool real,bool reWrite = false,MyAccount myAccount = null, List<MyStock> myStocks = null)
        {
            record = "";
            realTime = real;

            if(realTime)
            {
                buyStocks = new List<TradStock>();
                sellStocks = new List<TradStock>();
                if (reWrite)
                {
                    ResetAccountAndStock();
                }
            }
        }
        public static void ResetAccountAndStock()
        {

            MyAccount myAccount = new MyAccount
                {
                    ID = 1,
                    AccountName = "Test",
                    AccountPassword = "Test",
                    Fund = 500000
                };
            Base.AccountDatabase.SaveAccountAsync(myAccount).Wait();
            Base.MyStockDatabase.DeleteMyStockAsync().Wait();
        }
        public static bool CheckIfTradTime()
        {
            DateTime now = DateTime.Now;
            if(now.DayOfWeek == DayOfWeek.Sunday || now.DayOfWeek == DayOfWeek.Saturday)
            {
                return false;
            }
            int time = int.Parse(now.ToString("HHmm"));
            if (time < 930 || (time > 1130 & time < 1300) || time > 1500) return false;
            return true;
        }

        public int CanBuyNum(double tradPrice)
        {
            double myFund = fakeFund;
            if (realTime)
            {
                myFund = Base.AccountDatabase.GetAccountAsync().Result.Fund;

            }
            if (myFund > 1000)
            {
                int num = (int)(Math.Floor(myFund / tradPrice / 100 - 1) * 100);
                if (num <= 0) return 0;
                return num;
            }
            return 0;

        }
        public int CanSellStockNum(string code)
        {
            if(realTime)
            {
                MyStock myStock = Base.MyStockDatabase.GetStockAsync(code).Result;
                if (myStock == null) return 0;
                if (myStock.StockNum > 0) return myStock.StockNum;
            }
            else
            {
                foreach(var temp in fakeStocks)
                {
                    if(temp.StockCode == code)
                    {
                        return temp.StockNum;
                    }
                }
            }

            return 0;
        }
        public bool BuyAtMarket(string code)
        {
            double tradPrice;
            if (realTime)
            {
                RealTimeInfo realTimeInfo = GetRealTimeInfo.GetStockRealTimeInfo(code);
                tradPrice = realTimeInfo.sell1Price;
            }
            else
            {
                Base.CurrentCode = code;
                Stock dayData = Base.StockDatabase.GetStockAsync(date).Result;
                if(dayData==null)
                {
                    if (isRecord) record += string.Format("{0} 未获取到{1} 数据\r\n", date, code);
                    return false;
                }

                tradPrice = dayData.ClosePrice;
            }

            
            return BuyAtPrice(code, CanBuyNum(tradPrice), tradPrice);
        }
        public bool BuyAtMarket(string code, int num)
        {
            double tradPrice;
            if (realTime)
            {
                RealTimeInfo realTimeInfo = GetRealTimeInfo.GetStockRealTimeInfo(code);
                tradPrice = realTimeInfo.sell1Price;
            }
            else
            {
                Base.CurrentCode = code;
                Stock dayData = Base.StockDatabase.GetStockAsync(date).Result;
                tradPrice = dayData.ClosePrice;
            }
            return BuyAtPrice(code, num, tradPrice);
        }
        public bool BuyAtPrice(string code, double tradPrice)
        {
            double myFund = fakeFund;
            if (realTime)
            {
                myFund = Base.AccountDatabase.GetAccountAsync().Result.Fund;
            }
            
            int num = (int)(Math.Floor(myFund / tradPrice / 100 - 1) * 100);
            if (num <= 0) return false;
            return BuyAtPrice(code, num, tradPrice);
        }
        public bool BuyAtPrice(string code, int num, double tradPrice)
        {
            if (num == 0) return false;
            if (realTime)
            {
                TradStock buy = new TradStock
                {
                    tCode = code,
                    tNum = num,
                    tPrice = tradPrice
                };
                if (buyStocks == null)
                {
                    buyStocks = new List<TradStock>();
                }
                buyStocks.Add(buy);
                string temp = string.Format("准备以价格{0}买入{1} {2} 手\r\n", tradPrice, code, num);
                if (isRecord) record += temp;
                if(isOnClound)
                {
                    WxPusher.HttpGet(temp);
                }
 
                return true;
                
            }
            Base.CurrentCode = code;
            Stock dayData = Base.StockDatabase.GetStockAsync(date).Result;
            if (dayData == null) return false;
            if (dayData.LowPrice > tradPrice) return false;
            double myFund = fakeFund;
            int myHand = (int)Math.Floor((myFund / tradPrice) / 100 - 1) * 100;
            if (myHand <= 0) return false;
            
            double newFund = myFund - tradPrice * myHand - Math.Max(tradPrice * myHand * myCommissionRate, minCommission);
            if (newFund < 0)
            {
                return false;
            }
            fakeFund = newFund;
            if (isRecord) record += string.Format("{0} 买入 {1} {2} 手 ，价格 {5}, 持有现金从 {3} 变为 {4}\r\n", date, code, myHand, myFund, newFund, tradPrice);
            foreach(var temp in fakeStocks)
            {
                if(temp.StockCode == code)
                {
                    temp.StockNum += myHand;
                    myFund = newFund;
                    return true;
                }
            }
            fakeStocks.Add(new MyStock
            {
                StockCode = code,
                StockNum = myHand
            });
            return true;
        }

        public bool SellAtMarket(string code)
        {
            double tradPrice;
            if (realTime)
            {
                RealTimeInfo realTimeInfo = GetRealTimeInfo.GetStockRealTimeInfo(code);
                tradPrice = realTimeInfo.buy1Price;
            }
            else
            {
                Base.CurrentCode = code;
                Stock dayData = Base.StockDatabase.GetStockAsync(date).Result;
                tradPrice = dayData.ClosePrice;
            }
            return SellAtPrice(code, CanSellStockNum(code), tradPrice);
        }
        public bool SellAtMarket(string code, int num)
        {
            double tradPrice;
            if (realTime)
            {
                RealTimeInfo realTimeInfo = GetRealTimeInfo.GetStockRealTimeInfo(code);
                tradPrice = realTimeInfo.buy1Price;
            }
            else
            {
                Base.CurrentCode = code;
                Stock dayData = Base.StockDatabase.GetStockAsync(date).Result;
                tradPrice = dayData.ClosePrice;
            }
            return SellAtPrice(code, num, tradPrice);
        }
        public bool SellAtPrice(string code, double tradPrice)
        {
            foreach (var temp in fakeStocks)
            {
                if(temp.StockCode == code)
                {
                    return SellAtPrice(code, temp.StockNum, tradPrice);
                }
            }
            return false;
        }
        public bool SellAtPrice(string code, int num, double tradPrice)
        {
            if (num == 0) return false;
            if (realTime)
            {
                TradStock sell = new TradStock {
                tCode = code,
                tNum = num,
                tPrice = tradPrice};
                if(sellStocks == null)
                {
                    sellStocks = new List<TradStock>();
                }
                sellStocks.Add(sell);
                string temp = string.Format("准备以价格{0}卖出{1} {2} 手\r\n", tradPrice, code, num);
                if (isRecord) record += temp;
                if (isOnClound)
                {
                    WxPusher.HttpGet(temp);
                }


                return true;

            }
            Base.CurrentCode = code;
            Stock dayData = Base.StockDatabase.GetStockAsync(date).Result;
            if (tradPrice > dayData.HighPrice) return false;
            
            double newFund = fakeFund + tradPrice * num * (1 - myTax) - Math.Max(tradPrice * num * myCommissionRate, minCommission);
            foreach (var temp in fakeStocks)
            {
                temp.StockNum -= num;
            }
            if (isRecord) record += string.Format("{0} 卖出 {1} {2} 手，价格 {5}, 现金从 {3} 变为 {4}\r\n", date, code, num, fakeFund, newFund, tradPrice);
            fakeFund = newFund;
            return true;

        }

        //检查状态
        public static TradStatus CheckStatus()
        {
            if (!realTime) return TradStatus.NotReal;
            if (buyStocks.Count == 0 & sellStocks.Count == 0) return TradStatus.NotInSellOrBuy;
            if(buyStocks!= null & buyStocks.Count > 0)
            {
                foreach(TradStock buyStock in buyStocks)
                {
                    RealTimeInfo realTimeInfo = GetRealTimeInfo.GetStockRealTimeInfo(buyStock.tCode);
                    if(realTimeInfo.sell1Price <= buyStock.tPrice)
                    {
                        MyAccount myAccount = Base.AccountDatabase.GetAccountAsync().Result;
                        double newFund = myAccount.Fund - buyStock.tPrice * buyStock.tNum - Math.Max(buyStock.tPrice * buyStock.tNum * myCommissionRate, minCommission);
                        if (newFund < 0)
                        {
                            buyStocks.Remove(buyStock);
                            return TradStatus.InSellOrBuy;
                        }
                        WxPusher.HttpGet(string.Format("{0} 买入 {1} {2} 手 ，价格 {5}, 持有现金从 {3} 变为 {4}\r\n", DateTime.Now.ToString("yyyy年MM月dd日hh时mm分ss秒"), buyStock.tCode, buyStock.tNum, myAccount.Fund, newFund, buyStock.tPrice));
                        MyStock myStock = Base.MyStockDatabase.GetStockAsync(buyStock.tCode).Result;
                        if (myStock == null)
                        {
                            myStock = new MyStock
                            {
                                StockCode = buyStock.tCode,
                                StockNum = buyStock.tNum
                            };
                        }
                        else
                        {
                            myStock.StockNum += buyStock.tNum;
                        }
                        buyStocks.Remove(buyStock);
                        //扣钱
                        myAccount.Fund = newFund;
                        Base.AccountDatabase.SaveAccountAsync(myAccount).Wait();
                        //买了股票
                        Base.MyStockDatabase.SaveMyStockAsync(myStock).Wait();
                        return TradStatus.InSellOrBuy;
                    }
                }
            }
            if(sellStocks != null & sellStocks.Count > 0)
            {
                foreach (TradStock sellStock in sellStocks)
                {
                    RealTimeInfo realTimeInfo = GetRealTimeInfo.GetStockRealTimeInfo(sellStock.tCode);
                    if (realTimeInfo.buy1Price >= sellStock.tPrice)
                    {
                        MyStock myStock = Base.MyStockDatabase.GetStockAsync(sellStock.tCode).Result;
                        if (myStock == null || myStock.StockNum < sellStock.tNum)
                        {
                            sellStocks.Remove(sellStock);
                            return TradStatus.InSellOrBuy;
                        }
                        MyAccount myAccount = Base.AccountDatabase.GetAccountAsync().Result;
                        double newFund = myAccount.Fund + sellStock.tPrice * sellStock.tNum * (1 - myTax) - Math.Max(sellStock.tPrice * sellStock.tNum * myCommissionRate, minCommission);
                        if (sellStock.tNum == myStock.StockNum)
                        {
                            Base.MyStockDatabase.DeleteMyStockAsync(myStock);

                        }
                        else
                        {
                            myStock.StockNum -= sellStock.tNum;
                            Base.MyStockDatabase.SaveMyStockAsync(myStock);
                        }
                        WxPusher.HttpGet(string.Format("{0} 卖出 {1} {2} 手，价格 {5}, 现金从 {3} 变为 {4}\r\n", DateTime.Now.ToString("yyyy年MM月dd日hh时mm分ss秒"), sellStock.tCode, sellStock.tNum, myAccount.Fund, newFund, sellStock.tPrice));
                        sellStocks.Remove(sellStock);
                        myAccount.Fund = newFund;
                        Base.AccountDatabase.SaveAccountAsync(myAccount).Wait();
                        return TradStatus.InSellOrBuy;
                    }
                }
            }
            if ((buyStocks == null || buyStocks.Count == 0) & (sellStocks == null || sellStocks.Count == 0)) return TradStatus.NotInSellOrBuy;
            return TradStatus.InSellOrBuy;
        }

        public double GetAllMyAsset()
        {
            double myAsset = fakeFund;
            List<MyStock> myStocks = fakeStocks;
            if (realTime)
            {
                myAsset = Base.AccountDatabase.GetAccountAsync().Result.Fund;
                myStocks = Base.MyStockDatabase.GetAllStockAsync().Result;
            }
            if (myStocks == null) return myAsset;
            foreach(MyStock stock in myStocks)
            {
                if(stock.StockNum > 0)
                {
                    Base.CurrentCode = stock.StockCode;
                    myAsset += Base.StockDatabase.GetStockAsync(date).Result.ClosePrice * stock.StockNum;
                }
            }
            return myAsset;
        }
    }
}
